package fr.ensisa.sunspot.actor.osc;

import osc.as.OSCMessage;
import osc.as.OSCPacket;
import fr.ensisa.sunspot.enums.UINT;
import fr.ensisa.sunspot.enums.bVk;
import fr.ensisa.sunspot.enums.dwEvents;
import fr.ensisa.sunspot.enums.dwFlags;
import fr.ensisa.sunspot.event.DoubleEvent;
import fr.ensisa.sunspot.event.DoubleIntegerEvent;
import fr.ensisa.sunspot.event.DwFlagsEvent;
import fr.ensisa.sunspot.event.IEvent;
import fr.ensisa.sunspot.event.IntegerEvent;
import fr.ensisa.sunspot.event.MessageEvent;
import fr.ensisa.sunspot.event.MouseEvent;
import fr.ensisa.sunspot.event.StringEvent;
import fr.ensisa.sunspot.event.TripleEvent;

public class OscTranslator {
	public static String INTEGER_SELECTOR = "/1";
	public static String DOUBLE_SELECTOR = "/2";
	public static String TRIPLE_SELECTOR = "/3";
	public static String DOUBLE_INT_SELECTOR = "/4";
	public static String DW_FLAGS_EVENT = "/5";
	public static String MESSAGE_SELECTOR = "/6";
	public static String MOUSE_SELECTOR = "/7";
	public static String STRING_SELECTOR = "/8";
	

	public static OSCPacket EventToOscPacket(IEvent event) {
		if(event instanceof IntegerEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.INTEGER_SELECTOR, 3);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new Integer(((IntegerEvent) event).getIntensity()));
			
			return m;
		}
		else if(event instanceof DoubleEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.DOUBLE_SELECTOR, 3);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new Double(((DoubleEvent) event).getIntensity()));
			
			return m;
		}
		else if(event instanceof TripleEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.TRIPLE_SELECTOR, 5);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new Double(((TripleEvent) event).getX()));
			m.setArgument(3, new Double(((TripleEvent) event).getY()));
			m.setArgument(4, new Double(((TripleEvent) event).getZ()));
			
			return m;
		}
		else if(event instanceof DoubleIntegerEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.DOUBLE_INT_SELECTOR, 4);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new Integer(((DoubleIntegerEvent) event).getX()));
			m.setArgument(3, new Integer(((DoubleIntegerEvent) event).getY()));
			
			return m;
		}
		else if(event instanceof DwFlagsEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.DW_FLAGS_EVENT, 4);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new Integer(((DwFlagsEvent) event).getbVk().value()));
			m.setArgument(3, new Integer(((DwFlagsEvent) event).getDwFlags().value()));
			
			return m;
		}
		else if(event instanceof MessageEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.MESSAGE_SELECTOR, 6);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new String(((MessageEvent) event).getWindow()));
			m.setArgument(3, new Integer(((MessageEvent) event).getUint().value()));
			m.setArgument(4, new Integer(((MessageEvent) event).getBvk().value()));
			m.setArgument(5, new Integer(((MessageEvent) event).getI()));
			
			return m;
		}
		else if(event instanceof MouseEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.MOUSE_SELECTOR, 6);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new Integer(((MouseEvent) event).getDwEvents().value()));
			m.setArgument(3, new Integer(((MouseEvent) event).getX()));
			m.setArgument(4, new Integer(((MouseEvent) event).getY()));
			m.setArgument(5, new Integer(((MouseEvent) event).getDwData()));
			
			return m;
		}
		else if(event instanceof StringEvent) {
			OSCMessage m = new OSCMessage(OscTranslator.STRING_SELECTOR, 3);
			int info = 0;
			info |= event.getMajor();
			info |= event.getMinor();
			info |= event.getState();
			
			m.setArgument(0, new Integer(info));
			m.setArgument(1, new String(event.getSource()));
			m.setArgument(2, new String(((StringEvent) event).getString()));	
			
			return m;
		}
		
		return new OSCMessage();
	}
	
	public static IEvent OscPacketToEvent(OSCPacket packet) {
		if(packet instanceof OSCMessage) {
			OSCMessage m = (OSCMessage) packet;
			Integer info = (Integer) m.argument(0);
			
			if(m.selector().equals(OscTranslator.INTEGER_SELECTOR)) {		
				IntegerEvent event = new IntegerEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				event.setIntensity((Integer) m.argument(2));
				
				return event;
			}
			else if(m.selector().equals(OscTranslator.DOUBLE_SELECTOR)) {
				DoubleEvent event = new DoubleEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				event.setIntensity((Double) m.argument(2));
				
				return event;
			}
			else if(m.selector().equals(OscTranslator.TRIPLE_SELECTOR)) {
				TripleEvent event = new TripleEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				event.setX((Double) m.argument(2));
				event.setY((Double) m.argument(3));
				event.setZ((Double) m.argument(4));
				
				return event;
			}
			else if(m.selector().equals(OscTranslator.DOUBLE_INT_SELECTOR)) {
				DoubleIntegerEvent event = new DoubleIntegerEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				event.setX((Integer) m.argument(2));
				event.setY((Integer) m.argument(3));
				
				return event;
			}
			else if(m.selector().equals(OscTranslator.DW_FLAGS_EVENT)) {
				DwFlagsEvent event = new DwFlagsEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				
				bVk b = getbVk((Integer) m.argument(2));
				dwFlags d = getDwFlags((Integer) m.argument(3));
				
				if(b == null || d == null)
					return null;
				
				event.setbVk(b);
				event.setDwFlags(d);
				
				return event;
			}
			else if(m.selector().equals(OscTranslator.MESSAGE_SELECTOR)) {
				MessageEvent event = new MessageEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				event.setWindow((String) m.argument(2));
				
				UINT u = getUnit((Integer) m.argument(3));
				bVk b = getbVk((Integer) m.argument(4));
				
				if(u == null || b == null)
					return null;
				
				event.setUint(u);
				event.setBvk(b);
				
				event.setI((Integer) m.argument(5));
				
				return event;
			}
			else if(m.selector().equals(OscTranslator.MOUSE_SELECTOR)) {
				MouseEvent event = new MouseEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				
				dwEvents d = getDwEvents((Integer) m.argument(2));
				
				if(d == null)
					return null;
				
				event.setDwEvents(d);
				event.setX((Integer) m.argument(3));
				event.setY((Integer) m.argument(4));
				event.setDwData((Integer) m .argument(5));
				
				return event;
			}
			else if(m.selector().equals(OscTranslator.STRING_SELECTOR)) {
				StringEvent event = new StringEvent(info & IEvent.FIELD_MAJOR, info & IEvent.FIELD_MINOR);
				event.setState(info & IEvent.FIELD_STATE);
				event.setSource((String) m.argument(1));
				event.setString((String) m.argument(2));
				
				return event;
			}
		}
		
		return null;
	}
	
	private static bVk getbVk(int i) {
		for(bVk b : bVk.values()) {
			if(i == b.value())
				return b;
		}
		
		return null;
	}
	
	private static dwFlags getDwFlags(int i) {
		for(dwFlags d : dwFlags.values()) {
			if(i == d.value())
				return d;
		}
		
		return null;
	}
	
	private static UINT getUnit(int i) {
		for(UINT u : UINT.values()) {
			if(i == u.value())
				return u;
		}
		
		return null;
	}
	
	private static dwEvents getDwEvents(int i) {
		for(dwEvents d : dwEvents.values()) {
			if(i == d.value())
				return d;
		}
		
		return null;
	}
}
